﻿using System;
using Hvam.SharePoint.Search.Query.Site.Models;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Taxonomy;

namespace Hvam.SharePoint.Search.Query.Site.ResultSteps
{
    internal class FieldExtractorResultStep : SiteSearchResultStep
    {
        public FieldExtractorResultStep(SiteSearchQuery query) : base(query)
        {
        }

        public override SiteSearchResult Process(SiteSearchResult result)
        {
            var item = result.ListItem;

            foreach (var property in Query.RequestedProperties)
            {
                if (!Query.RequestedFields.ContainsKey(property))
                {
                    continue;
                }

                var field = Query.RequestedFields[property];
                var key = property;
                if (result.Properties.ContainsKey(key))
                {
                    continue;
                }

                string value;

                switch (field.TypeAsString)
                {
                    case "TaxonomyFieldType":
                        var t = GetValue(item, field);
                        if (t is TaxonomyFieldValue)
                        {
                            var taxonomyFieldValue = (TaxonomyFieldValue) t;
                            value = taxonomyFieldValue.Label;
                        }
                        else
                        {
                            value = "SiteSearch: Unsupported taxonomy field value.";
                        }
                        break;
                    case "DateTime":
                        var dt = GetValue(item, field);
                        if (dt is DateTime)
                        {
                            var dateTime = (DateTime) dt;

                            value = SPUtility.CreateISO8601DateTimeFromSystemDateTime(dateTime.ToUniversalTime());
                        }
                        else
                        {
                            value = "SiteSearch: Invalid datetime value.";
                        }
                        break;
                    case "Boolean":
                        value = GetStringValue(GetValue(item, field));
                        break;
                    case "Number":
                        value = GetStringValue(GetValue(item, field));
                        break;
                    case "Choice":
                    case "Note":
                    case "Text":
                        value = GetStringValue(GetValue(item, field));
                        break;
                    case "User":
                        value = GetStringValue(GetValue(item, field));
                        if (!string.IsNullOrEmpty(value))
                        {
                            var v = field.GetFieldValue(value);
                            if (v is SPFieldLookupValue)
                            {
                                var lookupValue = (SPFieldLookupValue) v;
                                value = lookupValue.LookupValue;
                            }
                            else
                            {
                                value = "SiteSearch: Unsupported user field value.";
                            }
                        }
                        break;
                    default:
                        value = "SiteSearch: Unsupported field type.";
                    break;
                }

                result.Properties.Add(key, value);
            }

            return result;
        }

        private object GetValue(SPListItem item, SPField field)
        {
            try
            {
                if (item.ID == 0 && item.ParentList.HasExternalDataSource)
                {
                    return item[field.InternalName];
                }
                return item[field.Id];
            }
            catch (ArgumentException)
            {
                return null;
            }
        }

        private string GetStringValue(object @object)
        {
            return @object == null ? string.Empty : @object.ToString();
        }
    }
}
